{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#|default_exp data.unwindowed"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Unwindowed datasets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">Functionality that will allow you to create a dataset that applies sliding windows to the input data on the fly. This heavily reduces the size of the input data files, as only the original unwindowed data needs to be stored.\n",
    "\n",
    "I'd like to thank both **Thomas Capelle** (https://github.com/tcapelle)  and **Xander Dunn** (https://github.com/xanderdunn) for their contributions to make this code possible. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#|export\n",
    "from tsai.imports import *\n",
    "from tsai.utils import *\n",
    "from tsai.data.validation import *\n",
    "from tsai.data.core import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#|export\n",
    "class TSUnwindowedDataset():\n",
    "    _types = TSTensor, TSLabelTensor\n",
    "    def __init__(self, X=None, y=None, y_func=None, window_size=1, stride=1, drop_start=0, drop_end=0, seq_first=True, **kwargs):\n",
    "        store_attr()\n",
    "        if X is not None:\n",
    "            if X.ndim == 1: X = np.expand_dims(X, 1)\n",
    "            shape = X.shape\n",
    "            assert len(shape) == 2\n",
    "            if seq_first: \n",
    "                seq_len = shape[0]\n",
    "            else: \n",
    "                seq_len = shape[-1]\n",
    "            max_time = seq_len - window_size + 1 - drop_end\n",
    "            assert max_time > 0, 'you need to modify either window_size or drop_end as they are larger than seq_len'\n",
    "            self.all_idxs = np.expand_dims(np.arange(drop_start, max_time, step=stride), 0).T\n",
    "            self.window_idxs = np.expand_dims(np.arange(window_size), 0)\n",
    "            if 'split' in kwargs: self.split = kwargs['split']\n",
    "            else: self.split = None\n",
    "            self.n_inp = 1\n",
    "            if y is None: \n",
    "                self.loss_func = MSELossFlat()\n",
    "            else: \n",
    "                if (is_listy(y[0]) and isinstance(y[0][0], Integral)) or isinstance(y[0], Integral): \n",
    "                    self.loss_func = CrossEntropyLossFlat()\n",
    "                else: \n",
    "                    self.loss_func = MSELossFlat()\n",
    "\n",
    "    def __len__(self):\n",
    "        if not hasattr(self, \"split\"): return 0\n",
    "        elif self.split is not None: \n",
    "            return len(self.split)\n",
    "        else: \n",
    "            return len(self.all_idxs)\n",
    "\n",
    "    def __getitem__(self, idxs):\n",
    "        if self.split is not None:\n",
    "            idxs = self.split[idxs]\n",
    "        widxs = self.all_idxs[idxs] + self.window_idxs\n",
    "        if self.seq_first:\n",
    "            xb = self.X[widxs]\n",
    "            if xb.ndim == 3: xb = xb.transpose(0,2,1)\n",
    "            else: xb = np.expand_dims(xb, 1)\n",
    "        else:\n",
    "            xb = self.X[:, widxs].transpose(1,0,2)\n",
    "        if self.y is None:\n",
    "            return (self._types[0](xb),)\n",
    "        else:\n",
    "            yb = self.y[widxs]\n",
    "            if self.y_func is not None: \n",
    "                yb = self.y_func(yb)\n",
    "            return (self._types[0](xb), self._types[1](yb))\n",
    "    \n",
    "    def new_empty(self): \n",
    "        return type(self)(X=None, y=None)\n",
    "    \n",
    "    @property\n",
    "    def vars(self):\n",
    "        s = self[0][0] if not isinstance(self[0][0], tuple) else self[0][0][0]\n",
    "        return s.shape[-2]\n",
    "    @property\n",
    "    def len(self): \n",
    "        s = self[0][0] if not isinstance(self[0][0], tuple) else self[0][0][0]\n",
    "        return s.shape[-1]    \n",
    "\n",
    "\n",
    "class TSUnwindowedDatasets(FilteredBase):\n",
    "    def __init__(self, dataset, splits):\n",
    "        store_attr()\n",
    "    def subset(self, i):\n",
    "        return type(self.dataset)(self.dataset.X, y=self.dataset.y, y_func=self.dataset.y_func, window_size=self.dataset.window_size,\n",
    "                                  stride=self.dataset.stride, drop_start=self.dataset.drop_start, drop_end=self.dataset.drop_end, \n",
    "                                  seq_first=self.dataset.seq_first, split=self.splits[i])\n",
    "    @property\n",
    "    def train(self): \n",
    "        return self.subset(0)\n",
    "    @property\n",
    "    def valid(self): \n",
    "        return self.subset(1)\n",
    "    def __getitem__(self, i): return self.subset(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def y_func(y): return y.astype('float').mean(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This approach works with both univariate and multivariate data.\n",
    "\n",
    "* Univariate: we'll use a simple array with 20 values, one with the seq_len first (X0), the other with seq_len second (X1).\n",
    "* Multivariate: we'll use 2 time series arrays, one with the seq_len first (X2), the other with seq_len second (X3). No sliding window has been applied to them yet. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((20,),\n",
       " array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,\n",
       "        13., 14., 15., 16., 17., 18., 19.]),\n",
       " (1, 20),\n",
       " array([[ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,\n",
       "         13., 14., 15., 16., 17., 18., 19.]]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Univariate\n",
    "X0 = np.arange(20).astype(float)\n",
    "X1 = np.arange(20).reshape(1, -1).astype(float)\n",
    "X0.shape, X0, X1.shape, X1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((20, 3),\n",
       " (3, 20),\n",
       " array([[0.0e+00, 0.0e+00, 0.0e+00],\n",
       "        [1.0e+00, 1.0e+01, 1.0e+02],\n",
       "        [2.0e+00, 2.0e+01, 2.0e+02],\n",
       "        [3.0e+00, 3.0e+01, 3.0e+02],\n",
       "        [4.0e+00, 4.0e+01, 4.0e+02],\n",
       "        [5.0e+00, 5.0e+01, 5.0e+02],\n",
       "        [6.0e+00, 6.0e+01, 6.0e+02],\n",
       "        [7.0e+00, 7.0e+01, 7.0e+02],\n",
       "        [8.0e+00, 8.0e+01, 8.0e+02],\n",
       "        [9.0e+00, 9.0e+01, 9.0e+02],\n",
       "        [1.0e+01, 1.0e+02, 1.0e+03],\n",
       "        [1.1e+01, 1.1e+02, 1.1e+03],\n",
       "        [1.2e+01, 1.2e+02, 1.2e+03],\n",
       "        [1.3e+01, 1.3e+02, 1.3e+03],\n",
       "        [1.4e+01, 1.4e+02, 1.4e+03],\n",
       "        [1.5e+01, 1.5e+02, 1.5e+03],\n",
       "        [1.6e+01, 1.6e+02, 1.6e+03],\n",
       "        [1.7e+01, 1.7e+02, 1.7e+03],\n",
       "        [1.8e+01, 1.8e+02, 1.8e+03],\n",
       "        [1.9e+01, 1.9e+02, 1.9e+03]]),\n",
       " array([[0.0e+00, 1.0e+00, 2.0e+00, 3.0e+00, 4.0e+00, 5.0e+00, 6.0e+00,\n",
       "         7.0e+00, 8.0e+00, 9.0e+00, 1.0e+01, 1.1e+01, 1.2e+01, 1.3e+01,\n",
       "         1.4e+01, 1.5e+01, 1.6e+01, 1.7e+01, 1.8e+01, 1.9e+01],\n",
       "        [0.0e+00, 1.0e+01, 2.0e+01, 3.0e+01, 4.0e+01, 5.0e+01, 6.0e+01,\n",
       "         7.0e+01, 8.0e+01, 9.0e+01, 1.0e+02, 1.1e+02, 1.2e+02, 1.3e+02,\n",
       "         1.4e+02, 1.5e+02, 1.6e+02, 1.7e+02, 1.8e+02, 1.9e+02],\n",
       "        [0.0e+00, 1.0e+02, 2.0e+02, 3.0e+02, 4.0e+02, 5.0e+02, 6.0e+02,\n",
       "         7.0e+02, 8.0e+02, 9.0e+02, 1.0e+03, 1.1e+03, 1.2e+03, 1.3e+03,\n",
       "         1.4e+03, 1.5e+03, 1.6e+03, 1.7e+03, 1.8e+03, 1.9e+03]]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Multivariate\n",
    "X2 = np.arange(20).reshape(-1,1)*np.array([1, 10, 100]).reshape(1,-1).astype(float)\n",
    "X3 = np.arange(20).reshape(1,-1)*np.array([1, 10, 100]).reshape(-1,1).astype(float)\n",
    "X2.shape, X3.shape, X2, X3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, instead of applying SlidingWindow to create and save the time series that can be consumed by a time series model, we can use a dataset that creates the data on the fly. In this way we avoid the need to create and save large files. This approach is also useful when you want to test different sliding window sizes, as otherwise you would need to create files for every size you want to test.The dataset will create the samples correctly formatted and ready to be passed on to a time series architecture."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(TSTensor(samples:8, vars:1, len:5, device=cpu),\n",
       " tensor([[[ 0.,  1.,  2.,  3.,  4.]],\n",
       " \n",
       "         [[ 2.,  3.,  4.,  5.,  6.]],\n",
       " \n",
       "         [[ 4.,  5.,  6.,  7.,  8.]],\n",
       " \n",
       "         [[ 6.,  7.,  8.,  9., 10.]],\n",
       " \n",
       "         [[ 8.,  9., 10., 11., 12.]],\n",
       " \n",
       "         [[10., 11., 12., 13., 14.]],\n",
       " \n",
       "         [[12., 13., 14., 15., 16.]],\n",
       " \n",
       "         [[14., 15., 16., 17., 18.]]]),\n",
       " TSTensor(samples:8, vars:1, len:5, device=cpu),\n",
       " tensor([[[ 0.,  1.,  2.,  3.,  4.]],\n",
       " \n",
       "         [[ 2.,  3.,  4.,  5.,  6.]],\n",
       " \n",
       "         [[ 4.,  5.,  6.,  7.,  8.]],\n",
       " \n",
       "         [[ 6.,  7.,  8.,  9., 10.]],\n",
       " \n",
       "         [[ 8.,  9., 10., 11., 12.]],\n",
       " \n",
       "         [[10., 11., 12., 13., 14.]],\n",
       " \n",
       "         [[12., 13., 14., 15., 16.]],\n",
       " \n",
       "         [[14., 15., 16., 17., 18.]]]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "wds0 = TSUnwindowedDataset(X0, window_size=5, stride=2, seq_first=True)[:][0]\n",
    "wds1 = TSUnwindowedDataset(X1, window_size=5, stride=2, seq_first=False)[:][0]\n",
    "test_eq(wds0, wds1)\n",
    "wds0, wds0.data, wds1, wds1.data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(TSTensor(samples:8, vars:3, len:5, device=cpu),\n",
       " TSTensor(samples:8, vars:3, len:5, device=cpu),\n",
       " tensor([[[0.0000e+00, 1.0000e+00, 2.0000e+00, 3.0000e+00, 4.0000e+00],\n",
       "          [0.0000e+00, 1.0000e+01, 2.0000e+01, 3.0000e+01, 4.0000e+01],\n",
       "          [0.0000e+00, 1.0000e+02, 2.0000e+02, 3.0000e+02, 4.0000e+02]],\n",
       " \n",
       "         [[2.0000e+00, 3.0000e+00, 4.0000e+00, 5.0000e+00, 6.0000e+00],\n",
       "          [2.0000e+01, 3.0000e+01, 4.0000e+01, 5.0000e+01, 6.0000e+01],\n",
       "          [2.0000e+02, 3.0000e+02, 4.0000e+02, 5.0000e+02, 6.0000e+02]],\n",
       " \n",
       "         [[4.0000e+00, 5.0000e+00, 6.0000e+00, 7.0000e+00, 8.0000e+00],\n",
       "          [4.0000e+01, 5.0000e+01, 6.0000e+01, 7.0000e+01, 8.0000e+01],\n",
       "          [4.0000e+02, 5.0000e+02, 6.0000e+02, 7.0000e+02, 8.0000e+02]],\n",
       " \n",
       "         [[6.0000e+00, 7.0000e+00, 8.0000e+00, 9.0000e+00, 1.0000e+01],\n",
       "          [6.0000e+01, 7.0000e+01, 8.0000e+01, 9.0000e+01, 1.0000e+02],\n",
       "          [6.0000e+02, 7.0000e+02, 8.0000e+02, 9.0000e+02, 1.0000e+03]],\n",
       " \n",
       "         [[8.0000e+00, 9.0000e+00, 1.0000e+01, 1.1000e+01, 1.2000e+01],\n",
       "          [8.0000e+01, 9.0000e+01, 1.0000e+02, 1.1000e+02, 1.2000e+02],\n",
       "          [8.0000e+02, 9.0000e+02, 1.0000e+03, 1.1000e+03, 1.2000e+03]],\n",
       " \n",
       "         [[1.0000e+01, 1.1000e+01, 1.2000e+01, 1.3000e+01, 1.4000e+01],\n",
       "          [1.0000e+02, 1.1000e+02, 1.2000e+02, 1.3000e+02, 1.4000e+02],\n",
       "          [1.0000e+03, 1.1000e+03, 1.2000e+03, 1.3000e+03, 1.4000e+03]],\n",
       " \n",
       "         [[1.2000e+01, 1.3000e+01, 1.4000e+01, 1.5000e+01, 1.6000e+01],\n",
       "          [1.2000e+02, 1.3000e+02, 1.4000e+02, 1.5000e+02, 1.6000e+02],\n",
       "          [1.2000e+03, 1.3000e+03, 1.4000e+03, 1.5000e+03, 1.6000e+03]],\n",
       " \n",
       "         [[1.4000e+01, 1.5000e+01, 1.6000e+01, 1.7000e+01, 1.8000e+01],\n",
       "          [1.4000e+02, 1.5000e+02, 1.6000e+02, 1.7000e+02, 1.8000e+02],\n",
       "          [1.4000e+03, 1.5000e+03, 1.6000e+03, 1.7000e+03, 1.8000e+03]]]),\n",
       " tensor([[[0.0000e+00, 1.0000e+00, 2.0000e+00, 3.0000e+00, 4.0000e+00],\n",
       "          [0.0000e+00, 1.0000e+01, 2.0000e+01, 3.0000e+01, 4.0000e+01],\n",
       "          [0.0000e+00, 1.0000e+02, 2.0000e+02, 3.0000e+02, 4.0000e+02]],\n",
       " \n",
       "         [[2.0000e+00, 3.0000e+00, 4.0000e+00, 5.0000e+00, 6.0000e+00],\n",
       "          [2.0000e+01, 3.0000e+01, 4.0000e+01, 5.0000e+01, 6.0000e+01],\n",
       "          [2.0000e+02, 3.0000e+02, 4.0000e+02, 5.0000e+02, 6.0000e+02]],\n",
       " \n",
       "         [[4.0000e+00, 5.0000e+00, 6.0000e+00, 7.0000e+00, 8.0000e+00],\n",
       "          [4.0000e+01, 5.0000e+01, 6.0000e+01, 7.0000e+01, 8.0000e+01],\n",
       "          [4.0000e+02, 5.0000e+02, 6.0000e+02, 7.0000e+02, 8.0000e+02]],\n",
       " \n",
       "         [[6.0000e+00, 7.0000e+00, 8.0000e+00, 9.0000e+00, 1.0000e+01],\n",
       "          [6.0000e+01, 7.0000e+01, 8.0000e+01, 9.0000e+01, 1.0000e+02],\n",
       "          [6.0000e+02, 7.0000e+02, 8.0000e+02, 9.0000e+02, 1.0000e+03]],\n",
       " \n",
       "         [[8.0000e+00, 9.0000e+00, 1.0000e+01, 1.1000e+01, 1.2000e+01],\n",
       "          [8.0000e+01, 9.0000e+01, 1.0000e+02, 1.1000e+02, 1.2000e+02],\n",
       "          [8.0000e+02, 9.0000e+02, 1.0000e+03, 1.1000e+03, 1.2000e+03]],\n",
       " \n",
       "         [[1.0000e+01, 1.1000e+01, 1.2000e+01, 1.3000e+01, 1.4000e+01],\n",
       "          [1.0000e+02, 1.1000e+02, 1.2000e+02, 1.3000e+02, 1.4000e+02],\n",
       "          [1.0000e+03, 1.1000e+03, 1.2000e+03, 1.3000e+03, 1.4000e+03]],\n",
       " \n",
       "         [[1.2000e+01, 1.3000e+01, 1.4000e+01, 1.5000e+01, 1.6000e+01],\n",
       "          [1.2000e+02, 1.3000e+02, 1.4000e+02, 1.5000e+02, 1.6000e+02],\n",
       "          [1.2000e+03, 1.3000e+03, 1.4000e+03, 1.5000e+03, 1.6000e+03]],\n",
       " \n",
       "         [[1.4000e+01, 1.5000e+01, 1.6000e+01, 1.7000e+01, 1.8000e+01],\n",
       "          [1.4000e+02, 1.5000e+02, 1.6000e+02, 1.7000e+02, 1.8000e+02],\n",
       "          [1.4000e+03, 1.5000e+03, 1.6000e+03, 1.7000e+03, 1.8000e+03]]]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "wds2 = TSUnwindowedDataset(X2, window_size=5, stride=2, seq_first=True)[:][0]\n",
    "wds3 = TSUnwindowedDataset(X3, window_size=5, stride=2, seq_first=False)[:][0]\n",
    "test_eq(wds2, wds3)\n",
    "wds2, wds3, wds2.data, wds3.data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": "IPython.notebook.save_checkpoint();",
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/Users/nacho/notebooks/tsai/nbs/014_data.unwindowed.ipynb saved at 2022-11-09 12:45:30\n",
      "Correct notebook to script conversion! 😃\n",
      "Wednesday 09/11/22 12:45:33 CET\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "                <audio  controls=\"controls\" autoplay=\"autoplay\">\n",
       "                    <source src=\"data:audio/wav;base64,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\" type=\"audio/wav\" />\n",
       "                    Your browser does not support the audio element.\n",
       "                </audio>\n",
       "              "
      ],
      "text/plain": [
       "<IPython.lib.display.Audio object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#|eval: false\n",
    "#|hide\n",
    "from tsai.export import get_nb_name; nb_name = get_nb_name(locals())\n",
    "from tsai.imports import create_scripts; create_scripts(nb_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
